using System;
using System.Collections.Generic;
using System.Text;

using System.Xml.XPath;
using System.Xml.Xsl;


namespace BadHabit.Factory {

    /// <summary>
    /// Helps to send notification E-mails.
    /// </summary>
    class ProjectEmailMessage : System.Net.Mail.MailMessage {

        private System.Net.Mail.SmtpClient smtpClient = new System.Net.Mail.SmtpClient();



        public ProjectEmailMessage(string projectUId, string serverPath, string serverUrl) {

            try {
                Project = Factory.Current.RetriveProjectAndRolesOnly(projectUId);
            } catch (Exception) { }            

            ServerPath = serverPath;
            ServerUrl = serverUrl;            
            From = new System.Net.Mail.MailAddress(Properties.Settings.Default.FactoryEmailAccount);
            smtpClient.Host = Properties.Settings.Default.SMTPServerAddress;

            AdjustProjectDataSet();
        }
        

        private string DefaultSubject {
            get {
                if (Project == null)
                    return "SCRUM FACTORY - ALERT";
                if (Project.Project.Count == 0)
                    return "SCRUM FACTORY - ALERT";
                return Project.Project[0].ClientName + " - " + Project.Project[0].ProjectName + " [" + Project.Project[0].ProjectNumber.ToString("0000") + "]";
            }
        }

        public string ServerPath {
            get;
            set;
        }

        /// <summary>
        /// Gets and Sets the server path.
        /// This is used at the XSLT template in order to refer images urls.
        /// </summary>
        public string ServerUrl {
            get;
            set;
        }
        
        
        /// <summary>
        /// Sets the project used to create the message.
        /// </summary>        
        private Data.ProjectDataSet Project {
            get;
            set;
        }

        private void DefineBodyFrom(string templateFullPath) {

            if (Project == null)
                return;


            System.Xml.Xsl.XslCompiledTransform xslTrans = new XslCompiledTransform();            
            xslTrans.Load(templateFullPath);
            
            // the e-mail message
            this.IsBodyHtml = true;

            Project.Namespace = "";
            XPathDocument xPathDoc = new XPathDocument(new System.IO.StringReader(Project.GetXml()));

            StringBuilder sb = new StringBuilder();
            System.IO.StringWriter writer = new System.IO.StringWriter(sb);

            xslTrans.Transform(xPathDoc, null, writer);
            writer.Close();

            Body = writer.ToString();            
        }

        private void AdjustProjectDataSet() {


            if (Project == null)
                return;

            double budgetIndicator = 0.0;
            double qualityIndicator = 0.0;
            double velocityIndicator = 0.0;
            double deadlineIndicator = 0.0;

            try {
                Data.ProjectPerformanceDataSet.ProjectPerformanceRow ind = Factory.Current.RetriveProjectPerformanceIndicators(Project.Project[0].ProjectUId);
                if (ind != null) {
                    budgetIndicator = ind.PctBudgetBurned;
                    qualityIndicator = ind.PctBugEffort;
                    velocityIndicator = ind.Velocity;
                    deadlineIndicator = ind.HoursAhead;
                }
            } catch (Exception) { }

            if (!Project.Project.Columns.Contains("BudgetIndicator"))
                Project.Project.Columns.Add("BudgetIndicator", typeof(double));
            Project.Project[0]["BudgetIndicator"] = budgetIndicator;

            if (!Project.Project.Columns.Contains("QualityIndicator"))
                Project.Project.Columns.Add("QualityIndicator", typeof(double));
            Project.Project[0]["QualityIndicator"] = qualityIndicator;

            if (!Project.Project.Columns.Contains("VelocityIndicator"))
                Project.Project.Columns.Add("VelocityIndicator", typeof(double));
            Project.Project[0]["VelocityIndicator"] = velocityIndicator;

            if (!Project.Project.Columns.Contains("DeadlineIndicator"))
                Project.Project.Columns.Add("DeadlineIndicator", typeof(double));
            Project.Project[0]["DeadlineIndicator"] = deadlineIndicator;


            // creates the well-formated date for the XML
            if(!Project.Project.Columns.Contains("EstimatedStartDateString"))
                Project.Project.Columns.Add("EstimatedStartDateString");
            Project.Project[0]["EstimatedStartDateString"] = Project.Project[0].EstimatedStartDate.ToShortDateString();

            // creates server path for the XML
            if (!Project.Project.Columns.Contains("ServerUrl"))
                Project.Project.Columns.Add("ServerUrl");
            Project.Project[0]["ServerUrl"] = ServerUrl;

            if (!Project.Project.Columns.Contains("ClientServerUrl"))
                Project.Project.Columns.Add("ClientServerUrl");
            Project.Project[0]["ClientServerUrl"] = Properties.Settings.Default.ClientLaunchServerUrl;
                                              
            
        }

        

        private void DefineSubjectAndDestinatariesForStatusChange() {


            if (Project == null)
                return;

            string unitFilter = "";

            switch (Project.Project[0].Status) {
                case (short)ProjectStatus.PROPOSAL_CREATION:
                    Subject = DefaultSubject + " - NEW OPORTUNITY";
                    unitFilter = "(Type =" + (short)TeamRoles.COMMERCIAL_GUY + " OR Type=" + (short)TeamRoles.SCRUM_MASTER + ")";
                    break;
                case (short)ProjectStatus.PROPOSAL_APPROVED:
                    Subject = DefaultSubject + " - PROJECT APPROVED!";
                    unitFilter = "(Type =" + (short)TeamRoles.COMMERCIAL_GUY + " OR Type=" + (short)TeamRoles.SCRUM_MASTER + " OR Type =" + (short)TeamRoles.TEAM + " OR Type =" + (short)TeamRoles.QUALITY_ASSURANCE + ")";                    
                    break;
                case (short)ProjectStatus.PROPOSAL_REJECTED:
                    Subject = DefaultSubject + " - PROJECT REJECTED";
                    unitFilter = "(Type =" + (short)TeamRoles.COMMERCIAL_GUY + " OR Type=" + (short)TeamRoles.SCRUM_MASTER + ")";
                    break;
                case (short)ProjectStatus.PROJECT_STARTED:
                    Subject = DefaultSubject + " - PROJECT STARTED!";
                    unitFilter = "(Type =" + (short)TeamRoles.COMMERCIAL_GUY + " OR Type=" + (short)TeamRoles.SCRUM_MASTER + " OR Type =" + (short)TeamRoles.TEAM + " OR Type =" + (short)TeamRoles.QUALITY_ASSURANCE + ")";                    
                    break;
                case (short)ProjectStatus.PROJECT_DONE:
                    Subject = DefaultSubject + " - PROJECT DONE!";
                    unitFilter = "(Type =" + (short)TeamRoles.COMMERCIAL_GUY + " OR Type=" + (short)TeamRoles.SCRUM_MASTER + " OR Type =" + (short)TeamRoles.TEAM + " OR Type =" + (short)TeamRoles.QUALITY_ASSURANCE + ")";                    
                    break;
                case (short)ProjectStatus.PROJECT_CANCELED:
                    Subject = DefaultSubject + " - PROJECT CANCELED!";
                    unitFilter = "(Type =" + (short)TeamRoles.COMMERCIAL_GUY + " OR Type=" + (short)TeamRoles.SCRUM_MASTER + " OR Type =" + (short)TeamRoles.TEAM + " OR Type =" + (short)TeamRoles.QUALITY_ASSURANCE + ")";                    
                    break;
             
            }

            DefineDestinataries(unitFilter);
            

        }

        private void DefineDestinataries(string unitFilter) {


            if (Project == null)
                return;

            To.Clear();
            foreach (Data.ProjectDataSet.BacklogItemUnitRow unit in Project.BacklogItemUnit.Select(unitFilter)) {
                foreach (Data.ProjectDataSet.ProjectRoleRow r in Project.ProjectRole.Select("UnitName='" + unit.UnitName + "'")) {
                    string emailAccount = FormatEmailAccount(r);
                    if (!String.IsNullOrEmpty(emailAccount))
                        To.Add(emailAccount);
                }
            }
        }


        /// <summary>
        /// Returns the email account for a given contact.
        /// </summary>
        /// <param name="c"></param>
        /// <returns></returns>
        private string FormatEmailAccount(Data.ProjectDataSet.ProjectRoleRow c) {            
            if (!String.IsNullOrEmpty(c.ContactEmail)) {                
                if (!String.IsNullOrEmpty(c.ContactName))
                    return c.ContactName.Replace("\\","-") + " <" + c.ContactEmail + ">";
                else
                    return c.ContactEmail;
            }
            return "";

            
        }

        /// <summary>
        /// Tries to send this message.
        /// </summary>
        /// <returns>True in case of success</returns>
        public void SendStatusChangeNotification() {


            if (Project == null)
                return;

            DefineSubjectAndDestinatariesForStatusChange();

            if (To.Count == 0)
                return;

            DefineBodyFrom(ServerPath + "\\App_Data\\ProjectEmailTemplates\\Status" + Project.Project[0].Status + ".xslt");

            smtpClient.Send(this);
        }


        internal void SendNewPlanNotification() {


            if (Project == null)
                return;

            if (Project.Project[0].Baseline == 0)
                return;
            
            DefineSubjectAndDestinatariesForNewPlan();

            if (To.Count == 0)
                return;

            DefineBodyFrom(ServerPath + "\\App_Data\\ProjectEmailTemplates\\NewPlan.xslt");

            smtpClient.Send(this);
        }



        internal void SendNewMemberNotification(Data.ProjectDataSet.ProjectRoleRow[] newMembers) {


            if (Project == null)
                return;

            DefineSubjectAndDestinatariesForNewMember(newMembers);


            if (To.Count == 0)
                return;

            DefineBodyFrom(ServerPath + "\\App_Data\\ProjectEmailTemplates\\NewMember.xslt");

            smtpClient.Send(this);

        }

        private void DefineSubjectAndDestinatariesForNewPlan() {

            if (Project == null)
                return;

            Subject = DefaultSubject + " - SPRINT PLAN " + Project.Project[0].Baseline;
            string unitFilter = "(Type=" + (short)TeamRoles.SCRUM_MASTER + " OR Type =" + (short)TeamRoles.TEAM + " OR Type =" + (short)TeamRoles.QUALITY_ASSURANCE + ")";                
            DefineDestinataries(unitFilter);
        }

        private void DefineSubjectAndDestinatariesForNewMember(Data.ProjectDataSet.ProjectRoleRow[] newMembers) {

            if (Project == null)
                return;

            Subject = DefaultSubject + " - NEW MEMBER";

            To.Clear();
            foreach (Data.ProjectDataSet.ProjectRoleRow r in newMembers) {
                Data.ProjectDataSet.BacklogItemUnitRow unit = Project.BacklogItemUnit.FindByUnitNameProjectUId(r.UnitName, Project.Project[0].ProjectUId);
                if (unit != null && unit.Type != (short)TeamRoles.CLIENT_CONTACT) {
                    string emailAccount = FormatEmailAccount(r);
                    if (!String.IsNullOrEmpty(emailAccount))
                        To.Add(emailAccount);
                }
            }
        }
    }
}
